package com.qdlc.p2p.biz.service.impl;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.google.common.base.Joiner;
import com.google.common.collect.Maps;
import com.google.common.primitives.Longs;
import com.google.gson.Gson;
import com.qd.p2p.adapter.param.QueryP2PBusinessParameter;
import com.qd.p2p.adapter.param.TransferAccountsParameter;
import com.qd.p2p.adapter.response.QueryP2PBusinessResponse;
import com.qd.p2p.adapter.response.TransferAccountsResponse;
import com.qd.p2p.baofoo.enums.AccountType;
import com.qd.p2p.baofoo.enums.FeeTakenOnType;
import com.qd.p2p.baofoo.enums.P2pBizType;
import com.qd.p2p.sina.pay.enums.IdentityType;
import com.qdlc.p2p.biz.processor.event.TppDispatchValueEvent;
import com.qdlc.p2p.biz.service.AbstractCollectService;
import com.qdlc.p2p.biz.service.CollectPayService;
import com.qdlc.p2p.common.constant.Global;
import com.qdlc.p2p.common.constant.NotifyUrl;
import com.qdlc.p2p.common.constant.RedEnvelopeType;
import com.qdlc.p2p.common.constant.RedStatus;
import com.qdlc.p2p.common.constant.SinaConstant;
import com.qdlc.p2p.common.constant.Summary;
import com.qdlc.p2p.common.constant.TradeCode;
import com.qdlc.p2p.common.constant.TradeStatus;
import com.qdlc.p2p.common.core.ReturnResult;
import com.qdlc.p2p.common.core.queue.QueueHandlers;
import com.qdlc.p2p.common.exception.RedEnvelopeException;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DataUtils;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.common.util.MessageUtil;
import com.qdlc.p2p.common.util.StringUtil;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.common.SystemConfigHelper.Nid;
import com.qdlc.p2p.dal.dao.TppDao;
import com.qdlc.p2p.dal.dao.UserDao;
import com.qdlc.p2p.dal.dao.UserRedEnvelopeDao;
import com.qdlc.p2p.dal.dto.Tpp;
import com.qdlc.p2p.dal.dto.TppTradeLog;
import com.qdlc.p2p.dal.dto.User;
import com.qdlc.p2p.dal.model.TppModel;
import com.qdlc.p2p.dal.model.TppTradeLogModel;
import com.qdlc.p2p.dal.util.UserUtils;

/**
 * 单笔转账服务类
 *
 * @author ygw
 * @version 1.1.0.0
 */
@Service("transferAccountsService")
public class TransferAccountsServiceImpl extends AbstractCollectService {

    private final static String BUSINESS_NAME = "单笔转账-";

    /** 红包ID */
    private ThreadLocal<long[]> redEnvelopeIds = new ThreadLocal<long[]>();

    /** 用户ID */
    private ThreadLocal<Long> userId = new ThreadLocal<Long>();

    /** 红包类型 */
    private ThreadLocal<Byte> redType = new ThreadLocal<Byte>();

    /** 红包使用场景 */
    private ThreadLocal<String> useType = new ThreadLocal<String>();
    //double money;

    /** 交易金额 */
    private ThreadLocal<Double> money = new ThreadLocal<Double>();
    
    /** 自动调度标识 1:自动，0:非自动 */
    private ThreadLocal<Integer> autoDispatch = new ThreadLocal<Integer>();

    @Resource
    private UserRedEnvelopeDao userRedEnvelopeDao;

    @Resource
    private TppDao tppDao;

    @Resource
    private UserDao userDao;
    
    @Resource
    @Qualifier("redEnvelopePayService")
    private CollectPayService redEnvelopePayService;

    @Override
    public String getCallBackUrl() {
        return WEB_URL.concat(NotifyUrl.RED_ENVELOPE_NOTIFY_COLLECT_URL).concat(".html");
    }

    @Override
    public String getBusinessName() {
        return BUSINESS_NAME;
    }

    @Override
    public void analyzePars(Object... pars) {
        this.autoDispatch.set(0);// 默认非自动
        if (pars.length != 4 && pars.length != 5) {
            throw new IllegalArgumentException("参数个数正确!");
        }
        try {
            this.redEnvelopeIds.set((long[]) pars[0]); // 红包兑现ID
            this.userId.set((Long) pars[1]);
            this.redType.set((Byte) pars[2]);
            this.useType.set((String) pars[3]);
            if (pars.length == 5) {
            	this.autoDispatch.set((Integer) pars[4]);
            }
            double moneyTemp = userRedEnvelopeDao.getTotalAmountByIds(redEnvelopeIds.get(), userId.get());
            moneyTemp = BigDecimalUtil.round(moneyTemp, 2);
            money.set(moneyTemp);
        } catch (Exception ex) {
            throw new IllegalArgumentException("参数类型正确!");
        }
    }

    @Override
    public TppTradeLog getTppTradeLog() {
        // 新浪备注
        Summary summary = redType.get() == RedEnvelopeType.CASH ? Summary.CASH_RED_ENVELOPE_EXCHAGE : Summary.VIRTUAL_RED_ENVELOPE_EXCHAGE;

        Map<String, Object> memoMap = Maps.newHashMap();
        memoMap.put("redType", redType.get());// 红包类型
        memoMap.put("redIds", redEnvelopeIds.get());// 兑现红包IDS
        memoMap.put("userId", userId.get());// 兑现用户ID
        memoMap.put("useType", useType.get());// 红包用途
        memoMap.put("money", money.get());// 红包用途
        Long tenderId = DataUtils.toLong(Global.getTransfer().get("tenderId"));
        if(tenderId != null) {
            memoMap.put("keyId", tenderId);// 投标ID
        }
        String toTppUserCustId = UserUtils.getUserTppCustId(userId.get());

        TppTradeLog tppTradeLog = new TppTradeLog();
        tppTradeLog.setTradeType(TradeCode.C1003.toString());
        tppTradeLog.setTppUserCustId(SystemConfigHelper.getSystemConfig(Nid.MERCHANT_ID).getValue()); // 平台支付
        tppTradeLog.setIdentityType(IdentityType.EMAIL.toString());
        tppTradeLog.setToTppUserCustId(toTppUserCustId);
        tppTradeLog.setMemo((new Gson()).toJson(memoMap));
        tppTradeLog.setMoney(money.get());
        tppTradeLog.setServiceType(summary.getSummaryType());
        tppTradeLog.setAutoDispatch(autoDispatch.get());// 自动调度标识 1:自动，0:非自动
        return tppTradeLog;
    }
    
    @Override
    public ReturnResult requestOrder(TppTradeLog tppTradeLog) {
    	TransferAccountsResponse response = null;
    	double amount = tppTradeLog.getMoney();
    	String orderNo = tppTradeLog.getOrderNo();
        try {
        	// 调用转账接口（平台转到用户）
    		TransferAccountsParameter parameter = new TransferAccountsParameter();
    		parameter.setOrderId(orderNo);
    		parameter.setAmount(amount);
    		parameter.setFee(0.00);
    		parameter.setFeeTakenOn(FeeTakenOnType.PAYER.getType());
    		parameter.setReqTime(tppTradeLog.getAddTime().getTime());
    		String transferType = SinaConstant.TRANSFER_TO_USER+"";
        	if  (transferType.equals(tppTradeLog.getMemo())) {
        		parameter.setPayerUserId(tppTradeLog.getTppUserCustId());
        		parameter.setPayeeUserId(tppTradeLog.getToTppUserCustId());
        		parameter.setPayerType(AccountType.MERCHANT.getType());
        		parameter.setPayeeType(AccountType.NORMAL.getType());
        	} else {
        		parameter.setPayerUserId(tppTradeLog.getTppUserCustId());
        		parameter.setPayeeUserId(tppTradeLog.getToTppUserCustId());
        		parameter.setPayerType(AccountType.NORMAL.getType());
        		parameter.setPayeeType(AccountType.MERCHANT.getType());
        	}
        	response = paySerivce.transferAccounts(parameter);
            
        } catch (Exception e) {
            // do nothing 调用失败
        }
        if (response != null && response.isSuccess()) {
            tppTradeLog.setRemark(getBusinessName().concat("处理成功"));
            tppTradeService.update(tppTradeLog);
        } else {
        	// 查询订单状态
        	QueryP2PBusinessResponse pBuResponse = null;
        	try {
            	QueryP2PBusinessParameter parameter = new QueryP2PBusinessParameter();
        		parameter.setOrderId(orderNo);
        		parameter.setType(P2pBizType.TRANSFER.getType());// 1-投标 2-满标 3-流标 4-还款 5-充值 6-提现 7-转账 8-用户信息
        		pBuResponse = paySerivce.queryP2PBusiness(parameter);
			} catch (Exception e) {
				// do nothing 调用失败
			}
        	if (pBuResponse != null && pBuResponse.getResult().size() > 0 && pBuResponse.getResult().get(0).getState() == 1) {// 处理成功
    		} else {
    			String message = response == null ? "RPC调用失败" : MessageFormat.format("{0}转账失败!ResCode:{1} ResMessage:{2}",
                        getBusinessName(), response.getResponseCode(),response.getResponseMsg());
                String responseMessage = response == null ? "RPC调用失败" : response.getResponseMsg();
                logger.info(message);

                // 置为废单
                tppTradeLog.setTradeStatus(TradeStatus.TRADE_STATUS_INVALID.getStatus());
                tppTradeLog.setRemark(getBusinessName().concat("提交失败-" + responseMessage));
                tppTradeService.update(tppTradeLog);

                requestOrderFail(tppTradeLog); // 请求失败处理
                return new ReturnResult(true, message);
    		}
        }
        return ReturnResult.SUCCESS;
    }

    @Override
    public boolean preCreateOrder() {
        // 红包类型
        String redTypeStr = redType.get() == RedEnvelopeType.CASH ? "现金红包" : "虚拟红包";
        // 检测红包是否可用
        boolean isCashEnvelope = userRedEnvelopeDao.checkCanUseRedEnvelope(redEnvelopeIds.get(), userId.get(), redType.get());
        if (isCashEnvelope == false) {
            String message = MessageFormat.format("无法兑现,请确认红包是否过期或非{0}!", redTypeStr);
            logger.info(message);
            throw new RedEnvelopeException(message, RedEnvelopeException.TYPE_JSON);
        }
        // 红包限制最低兑换金额,0代表不限制
        double limit = SystemConfigHelper.getDoubleValue(SystemConfigHelper.Nid.RED_ENVELOPE_EXCHANGE_LIMIT);
        // 统计可使用红包的总额,取小数点2位
        double redEnvelopeAmount = userRedEnvelopeDao.getTotalAmountByIds(redEnvelopeIds.get(), userId.get());
        redEnvelopeAmount = BigDecimalUtil.round(redEnvelopeAmount, 2);
        // 如果兑换金额小于限制金额则不允许兑换
        if (redEnvelopeAmount < limit) {
            throw new RedEnvelopeException(MessageUtil.getMessage("MF100002002"), RedEnvelopeException.TYPE_JSON);
        }
        return true;
    }

    @Override
    public void aftCreateOrder(TppTradeLog tppTradeLog) {
        //  红包冻结
        int userCount = userRedEnvelopeDao.changeStatus(redEnvelopeIds.get(), RedStatus.NO_USE, RedStatus.FREEZE);
        if (userCount != redEnvelopeIds.get().length) {
            throw new RedEnvelopeException("请确认红包状态是否可用!", RedEnvelopeException.TYPE_JSON);
        }
    }

    @Override
    public void requestOrderFail(TppTradeLog tppTradeLog) {
        // 解冻红包
        logger.error(tppTradeLog.getRemark().concat("红包解冻"));
        Map<String, Object> memoMap = DataUtils.getMemo(tppTradeLog.getMemo());
        long[] redEnvelopeIds = Longs.toArray((ArrayList) memoMap.get("redIds"));
        List<Long> ids = StringUtil.getRedIdList(redEnvelopeIds);
        byte redType = DataUtils.toByte(memoMap.get("redType")); // 红包类型
        long userId = DataUtils.toLong(memoMap.get("userId"));

        // 红包解冻
        userRedEnvelopeDao.changeStatus(redEnvelopeIds, RedStatus.FREEZE, RedStatus.NO_USE);

        // 保存调度任务信息
        // 排除手动兑现（手动兑现失败后可以重新兑现）
        if (redType == RedEnvelopeType.VIRTUAL) {
        	Tpp tpp = new Tpp();
            tpp.setStatus(TppModel.STATUS_FAIL);
            tpp.setRespDesc(tppTradeLog.getRemark());
            User toUser = userDao.getUserById(userId);
            tpp.setServiceType(TppModel.RED_ENVELOPE_EXCHANGE);
            tpp.setTppType(SinaConstant.TRADE_SERVICE_RED_ENVELOPE_EXCHAGE);
            tpp.setTppUserCustId(tppTradeLog.getTppUserCustId());
            tpp.setToUser(toUser);
            tpp.setToTppUserCustId(toUser.getTppUserCustId());
            tpp.setMoney(tppTradeLog.getMoney());
            tpp.setOrderId(tppTradeLog.getOrderNo());
            tpp.setOrderDate(DateUtil.dateStr7(tppTradeLog.getAddTime()));
            tpp.setExtended(Joiner.on(",").skipNulls().join(ids));
            tpp.setTradeType(tppTradeLog.getTradeType());
            tpp.setFlag(redType + "");
            tpp.setAddTime(DateUtil.getNow());
            tppDao.save(tpp);
            
            // 调度任务交由队列处理(延时处理)
            if (tppTradeLog.getAutoDispatch() != TppTradeLogModel.IS_AUTO) {// 防止重复处理
            	TppModel tppModel = TppModel.instance(tpp);
            	TppDispatchValueEvent tppDispatchValueEvent = new TppDispatchValueEvent();
            	tppDispatchValueEvent.setTppModel(tppModel);
                QueueHandlers.put(tppDispatchValueEvent);
            }
        }
    }

    @Override
    public void tradeFinish(TppTradeLog tppTradeLog, String depositStatus, double tradeAmount) {
        super.tradeFinishForStatus(tppTradeLog, depositStatus, tradeAmount);
    }

    @Override
    public void tradeSuccess(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeSuccessForStatus(tppTradeLog, depositStatus);
    }

    @Override
    public void tradeFail(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeFailForStatus(tppTradeLog, depositStatus);
        // 回调失败
        requestOrderFail(tppTradeLog);
    }
}